#pragma once

#include <iostream>
#include <vector>


#include "Sem.hpp"
#include "Mutex.hpp"

namespace RingBufferModule
{
    using namespace MutexModule;
    using namespace SemModule;

    template <typename T>
    class RingBuffer
    {
    public:

        RingBuffer(int cap)
        :_cap(cap)
        ,_p_step(0)
        ,_c_step(0)
        ,_ring(cap)
        ,_datasem(0)
        ,_spacesem(cap)
        {

        }

        //为什么不需要进行条件判断
        //信号量本身表示资源数目
        //只要P成功就表示一定有资源，不需要判断；如果不成功P就会失败，线程进入等待
        void Equeue(const T& in)
        {
            //生产者
            _spacesem.P();//申请空间，消耗空间

            {
                LockGuard lock(_p_lock);
                _ring[_p_step] = in;
                _p_step++;
                _p_step %= _cap;
            }

            _datasem.V();//生产数据，释放数据
        }

        void Pop(T *out)
        {
            //消费者
            _datasem.P();

            {
                LockGuard lock(_p_lock);
                *out = _ring[_c_step];
                _c_step++;
                _c_step %= _cap;
            }

            _spacesem.V();
        }

        ~RingBuffer()
        {

        }
    private:
        std::vector<T> _ring;//环，临界资源
        int _cap;           //总容量
        int _p_step;        //生产者位置
        int _c_step;        //消费者位置

        Sem _datasem;      //数据信号量
        Sem _spacesem;     //空间信号量

        Mutex _c_lock;
        Mutex _p_lock;
    };
}